/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-10     xu       the first version
 */
#include "chinese_date_api.h"

#include "cJSON.h"
#include "fal.h"
#include "gbk2utf8.h"
#include "http_api_utils.h"
#include "kvdb.h"
#include "time_utils.h"
#include "webclient.h"

#define DBG_TAG "cdate.api"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtthread.h>
#include <stdlib.h>

#define CHINESE_DATE_URL_FORMAT "http://193.149.161.197:8080/cn_date?d=%s"
#define CHINESE_DATE_URL_BUFFER_SIZE 128

chinese_date_t chinese_date_get(const struct tm* request_tm)
{
    if (request_tm == RT_NULL) {
        return RT_NULL;
    };

    const char* date = tm_to_date_str(request_tm);
    char* request_url = rt_calloc(CHINESE_DATE_URL_BUFFER_SIZE, sizeof(char));
    if (!request_url) {
        LOG_E("no memory for chinese date request URL!");
        return RT_NULL;
    }

    // preapre requesst URL
    rt_snprintf(request_url, CHINESE_DATE_URL_BUFFER_SIZE, CHINESE_DATE_URL_FORMAT, date);
    LOG_D("request_url = %s", request_url);

    // perform HTTP request
    char* response = RT_NULL;
    size_t resp_len = 0;
    if (http_get(request_url, &response, &resp_len) < 0) {
        // if (webclient_request(request_url, RT_NULL, RT_NULL, 0, (void**)&response, &resp_len) < 0) {
        LOG_E("webclient send get request failed.");
        rt_free(request_url);
        return RT_NULL;
    }
    rt_free(request_url);
    LOG_D("Got response data length: %d", resp_len);

    chinese_date_t cn_date = RT_NULL;
    if (resp_len > 0) {
        cn_date = chinese_date_from_json(response);
    }

    if (response) {
        web_free(response);
    }
    return cn_date;
}

void chinese_date_delete(chinese_date_t date)
{
    if (!date) {
        return;
    }
    SAFE_FREE(date->date);
    SAFE_FREE(date->lunardate);
    // SAFE_FREE(date->festival);
    // SAFE_FREE(date->lunar_festival);
    // SAFE_FREE(date->fitness);
    // SAFE_FREE(date->jieqi);
    // SAFE_FREE(date->lunarday);
    // SAFE_FREE(date->lunarmonth);
    // SAFE_FREE(date->taboo);
    SAFE_FREE(date);
}

chinese_date_t chinese_date_from_json(const char* text)
{
    if (text == RT_NULL) {
        LOG_E("text null!");
        return RT_NULL;
    }

    chinese_date_t cn_date = rt_calloc(1, sizeof(struct chinese_date));
    if (cn_date == RT_NULL) {
        LOG_E("no memory to create chinese date!");
        return RT_NULL;
    }

    cJSON* root = cJSON_Parse(text);
    copy_string_field(&cn_date->date, root, "date");
    copy_string_field(&cn_date->lunardate, root, "lunardate");
    // copy_string_field(&cn_date->lunar_festival, root, "lunar_festival");
    // copy_string_field(&cn_date->festival, root, "festival");
    // copy_string_field(&cn_date->fitness, root, "fitness");
    // copy_string_field(&cn_date->jieqi, root, "jieqi");
    // copy_string_field(&cn_date->lunarday, root, "lunarday");
    // copy_string_field(&cn_date->lunarmonth, root, "lunarmonth");
    // copy_string_field(&cn_date->taboo, root, "taboo");
    cJSON_Delete(root);
    return cn_date;
}

const char* chinese_date_to_json(chinese_date_t date)
{
    if (date == RT_NULL) {
        LOG_E("date null!");
        return RT_NULL;
    }

    cJSON* root = cJSON_CreateObject();
    if (root == RT_NULL) {
        LOG_E("no memory to create JSON object!");
        return RT_NULL;
    }

    int retval = 0;
    retval |= add_string_field(root, "date", date->date);
    retval |= add_string_field(root, "lunardate", date->lunardate);
    // retval |= add_string_field(root, "festival", date->festival);
    // retval |= add_string_field(root, "lunar_festival", date->lunar_festival);
    // retval |= add_string_field(root, "fitness", date->fitness);
    // retval |= add_string_field(root, "jieqi", date->jieqi);
    // retval |= add_string_field(root, "lunarday", date->lunarday);
    // retval |= add_string_field(root, "lunarmonth", date->lunarmonth);
    // retval |= add_string_field(root, "taboo", date->taboo);

    const char* text = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    return text;
}

static int cn_date_test(int argc, char* argv[])
{
    time_t time_seconds = time(NULL);
    struct tm tm_struct = {0};
    rt_memcpy(&tm_struct, localtime(&time_seconds), sizeof(tm_struct));
    rt_kprintf("current_tm: %s", asctime(&tm_struct));

    chinese_date_t cn_date = chinese_date_get(&tm_struct);
    if (!cn_date) {
        rt_kprintf("Get chinese date failed!\n");
        return -1;
    }
    chinese_date_delete(cn_date);
    return 0;
}
MSH_CMD_EXPORT(cn_date_test, "Chinese date test");

static kvdb_t kvdb = RT_NULL;

chinese_date_t chinese_date_kvdb_get(const struct tm* request_tm)
{
    if (kvdb == RT_NULL) {
        kvdb = kvdb_open(MATA_PART_NAME);
    }
    if (!kvdb) {
        LOG_E("kvdb init failed!");
        return RT_NULL;
    }

    // preallocate a buffer
    size_t json_len = 1024;
    char* json_str = rt_malloc(json_len);

    // query db
    const char* date_str = tm_to_date_str(request_tm);
    rt_bool_t retval = kvdb_get(kvdb, date_str, (uint8_t*)json_str, &json_len);
    if (retval != RT_TRUE) {
        rt_free((void*)json_str);
        LOG_D("No cached json %s!", date_str);
        return RT_NULL;
    }

    LOG_D("Got cached json %s for %s, %d", json_str, date_str, retval);
    chinese_date_t cn_date = chinese_date_from_json(json_str);
    rt_free((void*)json_str);
    return cn_date;
}

rt_bool_t chinese_date_kvdb_set(const struct tm* request_tm, chinese_date_t cn_date)
{
    if (kvdb == RT_NULL) {
        kvdb = kvdb_open(MATA_PART_NAME);
    }
    if (!kvdb) {
        LOG_E("kvdb init failed!");
        return RT_FALSE;
    }

    // convert object to json string(allocated)
    const char* json_str = chinese_date_to_json(cn_date);
    size_t json_len = strlen(json_str);

    // set to db
    const char* date_str = tm_to_date_str(request_tm);
    rt_bool_t retval = kvdb_set(kvdb, date_str, (const uint8_t*)json_str, json_len + 1);
    rt_free((void*)json_str);
    return retval;
}

static int cn_db_test(int argc, char* argv[])
{
    time_t current_time = time(NULL);
    struct tm current_tm = {0};
    rt_memcpy(&current_tm, localtime(&current_time), sizeof(current_tm));
    rt_kprintf("current: %s", asctime(&current_tm));

    chinese_date_t cn_date = chinese_date_get(&current_tm);
    rt_kprintf("get cn date from http: %s\n", cn_date ? "OK" : "FAIL");

    rt_bool_t set_ok = chinese_date_kvdb_set(&current_tm, cn_date);
    rt_kprintf("set cn date to db: %s\n", set_ok ? "OK" : "FAIL");
    kvdb_show(kvdb);

    chinese_date_t loaded = chinese_date_kvdb_get(&current_tm);
    rt_kprintf("get cn date from db: %s\n", loaded ? "OK" : "FAIL");

    chinese_date_delete(loaded);
    chinese_date_delete(cn_date);
    return 0;
}
MSH_CMD_EXPORT(cn_db_test, "Chinse date db test");